package com.vivz.baby.rest.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.vivz.baby.dao.LogDAO;
import com.vivz.baby.domain.Log;
import com.vivz.baby.util.SysoutUtil;

/**
 * Log Rest Service
 *
 * @author Vivek More
 */
@RestController
@RequestMapping(value = "/logdata", headers = "Accept=application/json, text/plain, */*", consumes = MediaType.ALL_VALUE)
public class LogService {

    private static final Log STUBBED_LOG;

    private static final List<Log> STUBBED_LIST;

    static {
	STUBBED_LOG = new Log();
	// LogService.STUBBED_LOG.setDiaper("stubbed DD");
	// LogService.STUBBED_LOG.setFormula(99);
	// LogService.STUBBED_LOG.setId(9999l);
	// LogService.STUBBED_LOG.setLeftBreast(99);
	// LogService.STUBBED_LOG.setRightBreast(99);
	// LogService.STUBBED_LOG.setPumped(99);
	// final Date today = new Date();
	// LogService.STUBBED_LOG.setTimestamp(today);
	// LogService.STUBBED_LOG.setUpdateTimestamp(today);

	STUBBED_LIST = Collections.singletonList(LogService.STUBBED_LOG);
    }

    @Autowired
    private LogDAO logDAO;

    @RequestMapping(value = "/{id}", method = { RequestMethod.GET })
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public Log findOne(@PathVariable final Long id) {
	SysoutUtil.sysout("findOne()");
	return logDAO.findOne(id);
    }

    @RequestMapping(method = { RequestMethod.GET })
    @ResponseStatus(HttpStatus.OK)
    public List<Log> findAll(Long userId) {
	final List<Log> allLogs = (List<Log>) logDAO.findByUserIdOrderByLogTimeDesc(userId);

	if (CollectionUtils.isEmpty(allLogs)) {
	    return LogService.STUBBED_LIST;
	} else {
	    SysoutUtil.sysout("found " + allLogs.size() + " logs.");
	}

	return new ArrayList<Log>(allLogs);
    }

    @RequestMapping(value = "/", method = { RequestMethod.POST, RequestMethod.PUT }, consumes = { "text/plain", "application/*" })
    public Log save(@RequestBody final Log log) {
	SysoutUtil.sysout("adding " + log);
	return logDAO.save(log);
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public void delete(@PathVariable final Long id) {
	SysoutUtil.sysout("Received request to delete id [" + id + "]");
	logDAO.delete(id);
    }

    @RequestMapping(value = "/sinceSunday", method = { RequestMethod.GET })
    @ResponseStatus(HttpStatus.OK)
    public List<Log> findAllSinceSunday(@PathVariable final Long userId) {

	final Calendar c = Calendar.getInstance();
	final Date now = c.getTime();
	c.set(Calendar.HOUR, c.getActualMinimum(Calendar.HOUR));
	c.set(Calendar.MINUTE, c.getActualMinimum(Calendar.MINUTE));
	c.set(Calendar.SECOND, c.getActualMinimum(Calendar.SECOND));
	c.add(Calendar.DAY_OF_WEEK, -(c.get(Calendar.DAY_OF_WEEK) - 1));
	final Date pastDate = c.getTime();

	final List<Log> allLogs = logDAO.findByUserIdAndLogTimeBetween(userId, pastDate, now);

	if (CollectionUtils.isEmpty(allLogs)) {
	    return LogService.STUBBED_LIST;
	} else {
	    SysoutUtil.sysout("found " + allLogs.size() + " logs.");
	}

	return new ArrayList<Log>(allLogs);
    }

    @RequestMapping(value = "/since1st", method = { RequestMethod.GET })
    @ResponseStatus(HttpStatus.OK)
    public List<Log> findAllSinceThe1st(@PathVariable final Long userId) {

	final Calendar c = Calendar.getInstance();
	final Date now = c.getTime();
	c.set(Calendar.HOUR, c.getActualMinimum(Calendar.HOUR));
	c.set(Calendar.MINUTE, c.getActualMinimum(Calendar.MINUTE));
	c.set(Calendar.SECOND, c.getActualMinimum(Calendar.SECOND));
	c.add(Calendar.DAY_OF_MONTH, -(c.get(Calendar.DAY_OF_MONTH) - 1));
	final Date pastDate = c.getTime();

	final List<Log> allLogs = logDAO.findByUserIdAndLogTimeBetween(userId, pastDate, now);

	if (CollectionUtils.isEmpty(allLogs)) {
	    return LogService.STUBBED_LIST;
	} else {
	    SysoutUtil.sysout("found " + allLogs.size() + " logs.");
	}

	return new ArrayList<Log>(allLogs);
    }

    @RequestMapping(value = "/lastNdays/{days}", method = { RequestMethod.GET })
    @ResponseStatus(HttpStatus.OK)
    public List<Log> findAllSinceLastNDays(@PathVariable final Long userId, @PathVariable final Long days) {

	final Calendar c = Calendar.getInstance();
	final Date now = c.getTime();
	c.set(Calendar.HOUR, c.getActualMinimum(Calendar.HOUR));
	c.set(Calendar.MINUTE, c.getActualMinimum(Calendar.MINUTE));
	c.set(Calendar.SECOND, c.getActualMinimum(Calendar.SECOND));
	c.add(Calendar.HOUR, -24 * days.intValue());
	final Date pastDate = c.getTime();

	final List<Log> allLogs = logDAO.findByUserIdAndLogTimeBetween(userId, pastDate, now);

	if (CollectionUtils.isEmpty(allLogs)) {
	    return LogService.STUBBED_LIST;
	} else {
	    SysoutUtil.sysout("found " + allLogs.size() + " logs.");
	}

	return new ArrayList<Log>(allLogs);
    }

    @RequestMapping(value = "/forTheMonthOf", method = { RequestMethod.POST })
    @ResponseStatus(HttpStatus.OK)
    public List<Log> findAllForTheMonthOf(@PathVariable final Long userId, @RequestBody final Date month) {

	final ArrayList<Log> logs = new ArrayList<Log>();
	SysoutUtil.sysout("received " + month + " as month.");

	if (month instanceof Date) {
	    final Date date = month;
	    final Date from = DateUtils.truncate(date, Calendar.MONTH);
	    final Calendar c = Calendar.getInstance();
	    c.setTime(date);
	    c.add(Calendar.MONTH, 1);
	    final Date to = DateUtils.truncate(c.getTime(), Calendar.MONTH);

	    final List<Log> allLogs = logDAO.findByUserIdAndLogTimeBetween(userId, from, to);

	    if (CollectionUtils.isEmpty(allLogs)) {
		return LogService.STUBBED_LIST;
	    } else {
		SysoutUtil.sysout("found " + allLogs.size() + " logs.");
	    }
	    logs.addAll(allLogs);
	}

	return logs;
    }

    @RequestMapping(value = "/{userId}/months", method = { RequestMethod.GET })
    @ResponseStatus(HttpStatus.OK)
    public List<Date> findMonths(@PathVariable Long userId) {
	final Set<Date> uniqueMonths = new HashSet<Date>();
	final List<Log> all = findAll(userId);
	if (CollectionUtils.isNotEmpty(all)) {
	    for (final Log log : all) {
		final Date month = DateUtils.truncate(log.getLogTime(), Calendar.MONTH);
		uniqueMonths.add(month);
	    }
	}
	final List<Date> months = new ArrayList<Date>(uniqueMonths);
	Collections.sort(months);
	return months;
    }

}
